home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / sysext / init / iconcolo.cpt / Source ƒ / 68K-Macros.asm next >
Encoding:
Assembly Source File  |  1989-02-16  |  9.2 KB  |  306 lines

  1. ;            +-------------------+
  2. ;            |            |
  3. ;            |     68K-Macros    |
  4. ;            |            |
  5. ;            +-------------------+
  6. ;
  7. ; 68K-Macros - macros to improve on the 68000's instruction mnemonics.
  8. ;
  9. ;    %W%\t%G% - SCCS Info
  10. ;
  11. ;   These macros are mostly intended to augment the 68000 instruction set.
  12. ; Some, like "compare", simply reverse the arguments to make it easier to
  13. ; understand.  Others facilitate creation of structured code.
  14. ;
  15. ; Revision History:
  16. ;
  17. ; 8806??   RPM    Start HyperTape II project.  All revision history for HyperTape
  18. ;        II is stored in the SCCS delta comment lines.
  19.  
  20. ; Macros to make the "cmp" instruction logical by un-reversing its arguments.
  21. ;
  22. macro    compare arg1,arg2 =
  23.     cmp.w {arg2},{arg1}
  24.     |
  25.  
  26. macro    compare_l arg1,arg2 =
  27.     cmp.l {arg2},{arg1}
  28.     |
  29.  
  30. macro    compare_b arg1,arg2 =
  31.     cmp.b {arg2},{arg1}
  32.     |
  33.  
  34. ; Lsl and Lsr by 16 bits, a common operation.
  35. ;
  36. macro    lsl_16 arg1 =
  37.     swap {arg1}
  38.     clr {arg1}
  39.     |
  40.  
  41. macro    lsr_16 arg1 =
  42.     clr {arg1}
  43.     swap {arg1}
  44.     |
  45.  
  46. ; Save/restore all registers, another common operation
  47. ;
  48. macro    SAVE_ALL =
  49.     movem.l d0-d7/a0-a4,-(sp)
  50.     |
  51.  
  52. macro    RESTORE_ALL =
  53.     movem.l (sp)+,d0-d7/a0-a4
  54.     |
  55.  
  56.  
  57. macro    _DebugStr =
  58.     dc.w $abff
  59.     |
  60.  
  61. ; Apparently, with MDS 2.0 the construct "pea 'MyText'" does not automatically
  62. ; declare the text and push the pc-relative address the way it used to in older
  63. ; versions.  Therefore, this macro was written.  It declares the text, jumps
  64. ; around the declaration, pushes the address, and invokes the trap.
  65. ;
  66. IF DBUG
  67. macro    DEBUGSTR text =
  68.     bra.s @9
  69. @8:
  70.     dc.b 16,{text}
  71.     dc.b 32, 32, 32, 32, 32, 32, 32, 32
  72.     dc.b 32, 32, 32, 32, 32, 32, 32, 32
  73.     .align 2
  74. @9:
  75.     pea @8
  76.     _DebugStr
  77.     |
  78. ENDIF
  79.  
  80. ; If you have a "DEBUG.STR" macro, just delete the "D" to temporarily "comment
  81. ; it out".  Of course, once debugging is complete the debugging macros should
  82. ; all be removed from the source.
  83. ;
  84. macro    EBUGSTR text =
  85.     ; does nothing
  86.     |
  87.  
  88. ; Macros for calling the debugLog2 subroutine.
  89. ;
  90. IF DBUG
  91. macro    DEBUGLOG value =
  92.     move    {value},-(sp)
  93.     bsr    debugLog2
  94.     |
  95. ENDIF
  96.  
  97. macro    EBUGLOG value =
  98.     ; does nothing
  99.     |
  100.  
  101. ; This is used to insert human-readable labels in code (to make up for the
  102. ; fact that in assembler you can't create labels which TMON will notice).
  103. ;
  104. IF DBUG
  105. macro    LABEL text =
  106.     dc.b '<<'
  107.     dc.b {text}
  108.     dc.b '>>'
  109.     .align 2
  110.     |
  111. ELSE
  112. macro    LABEL text =
  113.     ; nothing
  114.     |
  115. ENDIF
  116.  
  117. ; ===================== New stack-based subroutine macros =====================
  118. ;
  119. ; These macros make it easier to implement stack-based subroutines and
  120. ; functions, using Apple's standard stack-based calling sequence.  They save
  121. ; the programmer from having to think about how the frame pointer is saved, set
  122. ; up, and restored, and from having to figure out the total length of the local
  123. ; variable space (for use in the LINK instruction.)  Locals and parameters are
  124. ; referred to as locl_name(A6) and parm_name(A6), respectively.  The return
  125. ; value (if any) is referred to by (A6).
  126. ;    These macros use A6 as the parameter frame pointer, and restore its value
  127. ; when the subroutine ends.
  128. ;
  129. ;   When a subroutine is called by the standard Mac Pascal calling sequence,
  130. ; the stack looks something like this:
  131. ;
  132. ;             SP
  133. ;             |
  134. ;        ----+-----------+-----+-----------+-----------+---
  135. ; Stack grows|   return  |word |   long    |   return  | higher
  136. ;<-- this way|  address  |param|   param   |   value   | memory
  137. ;        ----+-----------+-----+-----------+-----------+---
  138. ;
  139. ; At the beginning of your subroutine, use the STACK_DECLARE macro, followed by
  140. ; one or more BYTE_PARAM, WORD_PARAM, and LONG_PARAM macros to declare the
  141. ; parameters of the subroutine. These macros set the assembler variables for
  142. ; the offsets to each parameter and the total length of the parameter space.
  143. ;    Declare the parameters in Pascal ordering, i.e. the same order that
  144. ; they're pushed onto the stack when the subroutine is called.
  145. ;
  146.  
  147. macro STACK_DECLARE =
  148.     last_param set 0
  149.     |
  150.  
  151.  
  152. macro BYTE_PARAM name =
  153.     last_param set last_param - 2
  154.     parm_{name} set last_param
  155.     |
  156.  
  157. macro WORD_PARAM name =
  158.     last_param set last_param - 2
  159.     parm_{name} set last_param
  160.     |
  161.  
  162. macro LONG_PARAM name =
  163.     last_param set last_param - 4
  164.     parm_{name} set last_param
  165.     |
  166.  
  167. ;    After declaring the parameters, use the STACK_BEGIN macro.  This macro
  168. ; saves A6 on the stack, then makes A6 point to the first byte after the last
  169. ; byte in the parameter space.  In other words, A6 points at the return value
  170. ; (if any). After STACK_BEGIN, the stack looks like this:
  171. ;
  172. ;             SP                      last_param(A6)    A6
  173. ;             |                       |                 |
  174. ;        ----+-----------+-----------+-----+-----------+-----------+---
  175. ; Stack grows|    old    |   return  |word |   long    |   return  | higher
  176. ;<-- this way|     A6    |  address  |param|   param   |   value   | memory
  177. ;        ----+-----------+-----------+-----+-----------+-----------+---
  178. ;
  179. ;    Please note that this is quite different from the LINK instruction, which
  180. ; is normally used to start a stack-based subroutine.  If we used LINK, the
  181. ; implementation of these macros would be somewhat more complex (because LINK
  182. ; requires knowledge of the size of the local variable space.)
  183. ;
  184. macro STACK_BEGIN =
  185.     move.l a6,-(sp)
  186.     lea 8-last_param(sp),a6
  187.     last_local set last_param - 8
  188.     |
  189.  
  190. ;    Next, use the macros BYTE_LOCAL, WORD_LOCAL, LONG_LOCAL, and ARRAY_LOCAL
  191. ; to declare the local variables.  These macros generate code to move the stack
  192. ; pointer down by the appropriate amount for each local variable.  After the
  193. ; locals are declared, the stack will look something like this:
  194. ;
  195. ;             SP                                                    A6
  196. ;             |                                                     |
  197. ;        ----+-----+-----+-----------+-----------+-----+-----------+-----------+---
  198. ; Stack grows|byte |word |    old    |   return  |word |   long    |   return  | higher
  199. ;<-- this way|local|local|     A6    |  address  |param|   param   |   value   | memory
  200. ;        ----+-----+-----+-----------+-----------+-----+-----------+-----------+---
  201. ;
  202. macro LONG_LOCAL name =
  203.     last_local set last_local - 4
  204.     locl_{name} set last_local
  205.     subq.l #4,sp
  206.     |
  207.  
  208. macro WORD_LOCAL name =
  209.     last_local set last_local - 2
  210.     locl_{name} set last_local
  211.     subq.l #2,sp
  212.     |
  213.  
  214. macro BYTE_LOCAL name =
  215.     last_local set last_local - 2
  216.     locl_{name} set last_local
  217.     subq.l #2,sp
  218.     |
  219.  
  220. ; NOTE:  When declaring an array local, the number of bytes specified MUST be
  221. ; an even number.  If it isn't, the Mac will reboot (really!) as soon as the
  222. ; subroutine tries to use the stack or call another subroutine.  (Trying to
  223. ; push or pop something on the stack when the SP is odd causes a "double bus
  224. ; fault", which causes the system to reboot.)
  225. ;
  226. macro ARRAY_LOCAL name,size =
  227.     last_local set last_local - {size}
  228.     locl_{name} set last_local
  229.     lea -{size}(sp),sp
  230.     |
  231.  
  232. ; After the parameters and locals are declared, start the actual code of the
  233. ; subroutine. Refer to a local or parameter "foo" by "locl_foo(A6)" or
  234. ; "parm_foo(A6)" as appropriate. Refer to the return value as "(A6)".
  235. ;
  236.  
  237. ; At the end of the subroutine, use the STACK_END macro in place of an RTS
  238. ; instruction. Note that the subroutine might have left some extra garbage on
  239. ; the stack. Therefore, the stack will look something like this:
  240. ;
  241. ;             SP                      last_param-8(A6)        last_param(A6)    A6
  242. ;             |                       |                       |                 |
  243. ;        ----+-----------+-----+-----+-----------+-----------+-----+-----------+-----------+---
  244. ; Stack grows|   extra   |byte |word |    old    |   return  |word |   long    |   return  | higher
  245. ;<-- this way|  garbage  |local|local|     A6    |  address  |param|   param   |   value   | memory
  246. ;        ----+-----------+-----+-----+-----------+-----------+-----+-----------+-----------+---
  247. ;
  248. ; STACK_END works in five steps:  First, it discards the garbage and the local
  249. ; variables by setting the SP to the location of the old A6.  Second, it pops
  250. ; the old A6 off the stack to restore A6.  Third, it copies the return address
  251. ; onto the top four bytes of the parameter space.  Then, it points the SP at
  252. ; this address.  Finally, it does an RTS, leaving the stack empty except for
  253. ; the return value.  (The reason RTS is used instead of JMP (A0) or something
  254. ; like that is to preserve A0.)
  255. ;     NOTE: It is done this way to make sure the macro works even if the
  256. ; subroutine has no parameters.
  257. ;
  258. macro STACK_END =
  259.     lea last_param-8(a6),sp
  260.     move.l (sp)+,a6
  261.     move.l (sp),-last_param(sp)
  262.     lea -last_param(sp),sp
  263.     rts
  264.     |
  265.  
  266. ; ==================== Example ==================
  267. ;
  268. ;    In this example, we want to write an assembly-language subroutine which
  269. ; is called in the same way as a Pascal routine with the following calling
  270. ; sequence:
  271. ;
  272. ; Function MyFilter (theDialog: DialogPtr; VAR theEvent: EventRecord;
  273. ;        VAR itemHit: INTEGER) : BOOLEAN;
  274. ;
  275. ;    We can write such a subroutine in the following way:
  276. ;
  277. ; _MyFilter
  278. ;    STACK_DECLARE
  279. ;    LONG_PARAM dialog_ptr
  280. ;    LONG_PARAM event_rec_ptr
  281. ;    LONG_PARAM item_hit_ptr
  282. ;
  283. ;    STACK_BEGIN
  284. ;    WORD_LOCAL foo
  285. ;    BYTE_LOCAL bar
  286. ;
  287. ;    SAVE_ALL        ; Save registers
  288. ;
  289. ;    move.w    #0, locl_bar(a6)    ; initialize locals
  290. ;    move.w    #$ffff, locl_foo(a6)
  291. ;
  292. ;    move.l    parm_event_rec_ptr(a6), a0    ; Get pointer to Event Record
  293. ;    move.w    evtNum(a0), d0            ; Get event code
  294. ;
  295. ;    ; (etc....)
  296. ;
  297. ;    move.w    d1, (a6)        ; Set value to return
  298. ;
  299. ;    RESTORE_ALL        ; restore registers
  300. ;
  301. ;    STACK_END        ; Return
  302. ;
  303.  
  304. ; end of 68K-Macros
  305.  
  306.